home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / PCTAGS15.ARJ / SHELL.C < prev    next >
C/C++ Source or Header  |  1991-10-07  |  44KB  |  1,181 lines

  1. /*
  2.  EPSHeader
  3.  
  4.    File: tags.c
  5.    Author: J. Kercheval
  6.    Created: Sun, 03/31/1991  14:59:48
  7. */
  8. /*
  9.  EPSRevision History
  10.  
  11.    J. Kercheval  Sun, 03/31/1991  16:24:01  creation
  12.    J. Kercheval  Sun, 03/31/1991  16:43:18  allow @filename listfile syntax
  13.    J. Kercheval  Tue, 05/14/1991  19:46:50  add tag_type
  14.    J. Kercheval  Wed, 05/15/1991  18:19:22  add -m and -o parameters
  15.    J. Kercheval  Wed, 05/15/1991  19:23:42  correctly parse for logfile
  16.    J. Kercheval  Wed, 05/15/1991  22:22:33  add the sort module
  17.    J. Kercheval  Thu, 05/16/1991  22:47:04  move file IO to fileio.c
  18.    J. Kercheval  Wed, 06/26/1991  23:03:55  move back to standard IO
  19.    J. Kercheval  Thu, 06/27/1991  21:43:11  create tags.h
  20.    J. Kercheval  Fri, 07/12/1991  23:04:23  revise command line parsing
  21.    J. Kercheval  Sat, 07/13/1991  11:29:02  update Usage()
  22.    J. Kercheval  Sat, 07/13/1991  12:47:34  finish argf parsing
  23.    J. Kercheval  Sat, 07/13/1991  13:06:16  move input routines to input.c
  24.    J. Kercheval  Sun, 07/14/1991  19:18:36  finish DoTags
  25.    J. Kercheval  Wed, 07/17/1991  22:18:58  allow append file logging
  26.    J. Kercheval  Thu, 07/18/1991  18:53:31  use fully qualified input pathname
  27.    J. Kercheval  Fri, 07/19/1991  20:15:43  allow sort only and non-sort options
  28.    J. Kercheval  Sun, 07/21/1991  17:38:00  add post processing
  29.    J. Kercheval  Mon, 07/22/1991  17:35:08  tweak log output and interface
  30.    J. Kercheval  Sat, 07/27/1991  20:38:36  remove ASM public flag and post processing hooks
  31.    J. Kercheval  Sat, 08/17/1991  23:03:47  enable c tagging
  32.    J. Kercheval  Sun, 08/25/1991  22:49:55  fix bug in ASM flag parsing
  33.    J. Kercheval  Thu, 08/29/1991  23:30:47  add CRC checking for virus check
  34.    J. Kercheval  Sat, 08/31/1991  23:56:02  add prototype flag
  35.    J. Kercheval  Thu, 09/05/1991  01:29:13  add input file name tracking
  36.    J. Kercheval  Thu, 09/05/1991  01:29:42  add -t flag
  37.    J. Kercheval  Thu, 09/05/1991  02:01:28  finish tag output logic
  38.    J. Kercheval  Thu, 09/05/1991  20:07:45  move arglist processing to seperate module
  39.    J. Kercheval  Thu, 09/05/1991  20:13:50  move MergeFile() to tagio.c
  40.    J. Kercheval  Tue, 09/10/1991  23:24:27  add ctrl-c handler
  41.    J. Kercheval  Wed, 09/11/1991  01:45:35  add usage comments for extern switch
  42.    J. Kercheval  Tue, 09/17/1991  19:43:23  add support for case_sensitive flag
  43.    J. Kercheval  Wed, 09/25/1991  13:42:28  support sorted arglists
  44.    J. Kercheval  Wed, 09/25/1991  16:02:18  check for duplicate file names at the command line level
  45.    J. Kercheval  Wed, 09/25/1991  22:47:37  supress tag file merge if not input files found
  46.    J. Kercheval  Tue, 10/01/1991  19:30:26  close all open files in external_cleanup()
  47.    J. Kercheval  Thu, 10/03/1991  13:55:09  add exclude file processing
  48.    J. Kercheval  Thu, 10/03/1991  16:46:07  improve list file parsing
  49.    J. Kercheval  Sat, 10/05/1991  10:56:18  add switch summary to usage
  50. */
  51.  
  52. #include <stdlib.h>
  53. #include <stdio.h>
  54. #include <string.h>
  55. #include <time.h>
  56. #include <signal.h>
  57.  
  58. #include "flags.h"
  59. #include "log.h"
  60. #include "wildfile.h"
  61. #include "sort.h"
  62. #include "ctag.h"
  63. #include "asmtag.h"
  64. #include "tagio.h"
  65. #include "viruscrc.h"
  66. #include "arglist.h"
  67.  
  68.  
  69. #define Author "J. Kercheval"
  70. #define Version "Tags Generator V1.5"
  71. #define CompileDate __TIMESTAMP__
  72.  
  73.  
  74. /* The following variables are pointers to the temporary filenames used as
  75.  * an intermediary files.  These are globals for use in external_cleanup()
  76.  * to delete any temporary files. */
  77. char *tmp_filename = NULL;
  78. char *tmp_tagfilename = NULL;
  79.  
  80.  
  81. /*----------------------------------------------------------------------------
  82.  *
  83.  * Print Usage
  84.  *
  85.  ---------------------------------------------------------------------------*/
  86.  
  87. void Usage(char *fname)
  88. {
  89.  
  90.     fprintf(stdout, "\n%s %s -- %s\n\n", Version, CompileDate, Author);
  91.     fprintf(stdout, "Usage: %s {[OPTIONS] [SOURCEFILE|@LISTFILE]}\n\n",
  92.             fname);
  93.     fprintf(stdout, "  -h for extended usage output to stdout\n");
  94.     fprintf(stdout, "  @LISTFILE for list file of input file names\n");
  95.     fprintf(stdout, "  -x{EXCLUDEFILE|@LISTFILE} to exclude files\n");
  96.     fprintf(stdout, "  -tTAGFILE to merge to a particular tag file\n");
  97.     fprintf(stdout, "  -lLOGFILE for log file (-l overwrites, -L appends)\n");
  98.     fprintf(stdout, "  -o[egsm] for output format\n");
  99.     fprintf(stdout, "  -a[fdlmsu] to specify assembly tagging\n");
  100.     fprintf(stdout, "  -c[dmstekuvcfpxi] to specify C tagging\n");
  101.     fprintf(stdout, "  -q will suppress normal status output\n");
  102.     fprintf(stdout, "  -r use relative pathnames in output\n");
  103.     fprintf(stdout, "  -n do not sort the tag output\n");
  104.     fprintf(stdout, "  -i use a case sensitive sort\n");
  105.     fprintf(stdout, "  -m for merge sort of the existing sorted files\n");
  106.     fprintf(stdout, "  -s sort input files only\n");
  107.     
  108.     exit(1);
  109. }
  110.  
  111.  
  112. /*----------------------------------------------------------------------------
  113.  *
  114.  * Print Extended Usage
  115.  *
  116.  ---------------------------------------------------------------------------*/
  117.  
  118. void Help(char *fname)
  119. {
  120.     char usage[][85] =
  121.     {
  122.         "  -h to obtain this help screen\n",
  123.         "  @LISTFILE for list file of input file names.  A list file is in the form",
  124.         "     of a response file (ie. a list of files seperated by some delimiter).",
  125.         "     The allowed delimiters for file seperation are '+', ',', ';' and normal",
  126.         "     whitespace.  This file allows commented lines by preceding any comment",
  127.         "     with a pound sign (#).  A comment is from the '#' to the end of the",
  128.         "     line and may start after any whitespace character\n",
  129.         "  -x{EXCLUDEFILE|@LISTFILE} excludes the files specified by EXCLUDEFILE",
  130.         "     or exclude all files listed in LISTFILE.\n",
  131.         "  -tTAGFILE to output to a (possibly existing) tag file and will result in",
  132.         "     previous tags for input files being removed from the output file.",
  133.         "     This tagfile is assumed to be in one of this utilities output formats.",
  134.         "     if -m or -s are used this switch is ignored (all output is to stdout).\n",
  135.         "  -lLOGFILE for output to a log file in a LISTFILE format suitable as input.",
  136.         "    behavior regarding existing files is determined by the case of the switch.",
  137.         "    -l  creates and outputs to a file overwriting any currently existing file",
  138.         "    -L  appends all output to the logfile if there is an already existing file\n",
  139.         "  -o[options] for output format to stdout or the tag file if -t switch is used",
  140.         "     e  Epsilon tag format     ( tokenString;fileName;characterOffset )",
  141.         "     g  GNU tag format         ( tokenString {tab} fileName {tab} /$line^/ )",
  142.         "     s  Space-Delimited format ( tokenString fileName lineNumber )",
  143.         "     m  MicroSoft Error format ( tokenString fileName(lineNumber) )\n",
  144.         "  -a[options] to specify assembly tagging and to detail the token types.",
  145.         "     Default tagging is -afdlmsu (80x86 assembly using MASM/TASM syntax)",
  146.         "     f  procedure labels       ( token proc )( proc token )",
  147.         "     d  definition labels      ( token equ const )( token db declaration )",
  148.         "     l  local labels           ( token label )( label token )( token: )",
  149.         "     m  macro labels           ( token macro )( macro token )",
  150.         "     s  struc labels           ( token struc )( struc token )",
  151.         "     u  union labels           ( token union )( union token )\n",
  152.         "  -c[options] to specify C tagging and to detail the token types. Default",
  153.         "     tagging options are -cdmstekuvcfpxi (standard ANSI 2.0 C/C++). Note that",
  154.         "     use of the -cx and the -ci switch are modifiers and will only be effective",
  155.         "     when other options are used (ie. -cpx must be specified to obtain extern",
  156.         "     prototypes, -cx alone yields nothing).  Note that the -cx and -ci modifier",
  157.         "     has no effect for define and macro tags which are tagged only according",
  158.         "     to the -cd and -cm switches respectively.  Additionally the -cx modifier",
  159.         "     is ignored for function tags.  The order of all of these options is not",
  160.         "     significant.",
  161.         "     d  defines                ( #define token statement )",
  162.         "     m  macro labels           ( #define token() statement )",
  163.         "     s  struct globals         ( struct token {} )",
  164.         "     t  typedef globals        ( typedef declaration token, token, ... )",
  165.         "     e  enum globals           ( enum token {} )",
  166.         "     k  enum konstants         ( enum { token, token, token, ...} )",
  167.         "     u  union globals          ( union token {} )",
  168.         "     v  global variable        ( declaration token, token = {}, token, ... )",
  169.         "     c  global class           ( class token: {} )",
  170.         "     f  function definitions   ( token() declaration {} )",
  171.         "     p  prototypes             ( token(, )",
  172.         "     x  extern defines         ( extern declaration )",
  173.         "     i  static declarations    ( static declaration )\n",
  174.         "  -q will suppress normal output to stderr and program version information",
  175.         "  -r use relative pathnames in output rather than fully qualified path names",
  176.         "  -n do not sort the tag output (Often used in conjunction with GNU style tags)",
  177.         "  -i use a case sensitive sort (Normally a case insensitive sort is used)\n",
  178.         "  The following result only in sorting of the input files (no tagging is done).",
  179.         "     Output is to stdout only (-t is ignored) when using these switches.",
  180.         "     -m for merge sort of the specified existing files (assumed to be sorted)",
  181.         "     -s sort input files only, all files are assumed to be in an unsorted state\n",
  182.         "  The TMP environment variable is used for temporary files.  The default for",
  183.         "     tags is to use C style tagging, the Epsilon tag file format, to sort",
  184.         "     the output before finally placing it in the output file (or stdout if -t",
  185.         "     is not used) and to be verbose and log activity to stderr.",
  186.         "  Each file specified on the command line or within a LISTFILE will be tagged",
  187.         "     only once regardless of the number of times it appears on the command",
  188.         "     line (This includes LISTFILEs as well as filenames and the files listed",
  189.         "     within LISTFILEs).",
  190.         "  All of the switches may be specified anywhere on the command line and with",
  191.         "     the exception of the style switches (-a, -c) are not position dependent.",
  192.         "     The style switches are active only for input files which fall after them",
  193.         "     on the command line and allows the specification of different tagging",
  194.         "     styles and types on a file by file basis.",
  195.         "  Input file and LISTFILE specifications allow the use of *IX shell style",
  196.         "     expressions (A subset of the standard UNIX regular expression syntax).",
  197.         "     This allows input file names such as \"*\", \"*t?*.c\" and \"*[e-gxyz]*\".",
  198.         "     Note that \"*\" in this case is completely equivalent to \"*.*\" in normal",
  199.         "     DOS usage. The use of \"*.\" will obtain files without extensions.",
  200.         "  This utility performs a CRC validation on itself to prevent corruption and",
  201.         "     viral infection from outside influences.  Modification of this file in",
  202.         "     any way will result in a failure of the internal CRC check.  On CRC",
  203.         "     failure the program will exit with a warning message.",
  204.         "\0"
  205.     };
  206.  
  207.     int i;                      /* index into help text array */
  208.  
  209.     fprintf(stdout, "\n%s %s -- %s\n\n", Version, CompileDate, Author);
  210.     fprintf(stdout, "Usage: %s {[OPTIONS] [SOURCEFILE|@LISTFILE]}\n\n",
  211.             fname);
  212.  
  213.     for (i = 0; usage[i][0]; i++) {
  214.         fprintf(stdout, "%s\n", usage[i]);
  215.     }
  216.  
  217.     exit(1);
  218. }
  219.  
  220.  
  221. /*----------------------------------------------------------------------------
  222.  *
  223.  * external_cleanup() removes the temporary file used here
  224.  *
  225.  ---------------------------------------------------------------------------*/
  226.  
  227. void external_cleanup(void)
  228. {
  229.     fcloseall();
  230.     if (tmp_filename != NULL)
  231.         remove(tmp_filename);
  232.     if (tmp_tagfilename != NULL)
  233.         remove(tmp_tagfilename);
  234. }
  235.  
  236.  
  237. /*----------------------------------------------------------------------------
  238.  *
  239.  * CtrlCHandler() cleans up and aborts
  240.  *
  241.  ---------------------------------------------------------------------------*/
  242.  
  243. void CtrlCHandler(void)
  244. {
  245.     /* Disallow CTRL+C during handler. */
  246.     signal(SIGINT, SIG_IGN);
  247.  
  248.     /* cleanup and abort */
  249.     external_cleanup();
  250.     abort();
  251. }
  252.  
  253.  
  254. /*----------------------------------------------------------------------------
  255.  *
  256.  * nextfile takes the list_file parameter and finds the next filename from
  257.  * the opened listfile.
  258.  *
  259.  ---------------------------------------------------------------------------*/
  260.  
  261. BOOLEAN nextfile(FILE * list_file, char *fname, int max_length)
  262. {
  263.     char white[] =
  264.     {
  265.         " \t\n\f\v\b\r,+;#"
  266.     };                          /* valid whitespace characters */
  267.  
  268.     char delim[] =
  269.     {
  270.         " \t\n\f\v\b\r,+;"
  271.     };                          /* end of filename characters */
  272.  
  273.     char *s;                    /* temporary char pointer */
  274.     char c;                     /* temporary char variable */
  275.  
  276.     int length;                 /* current length of fname */
  277.  
  278.     /* init */
  279.     s = fname;
  280.     *s = '\0';
  281.     length = 0;
  282.  
  283.     c = (char) fgetc(list_file);
  284.  
  285.     /* if end of file then we are done */
  286.     if (feof(list_file))
  287.         return FALSE;
  288.  
  289.     /* pass over whitespace */
  290.     while (strchr(white, c)) {
  291.         if (c == '#') {
  292.             while (c != '\n') {
  293.                 c = (char) fgetc(list_file);
  294.                 if (feof(list_file))
  295.                     return FALSE;
  296.             }
  297.         }
  298.         c = (char) fgetc(list_file);
  299.         if (feof(list_file))
  300.             return FALSE;
  301.     }
  302.  
  303.     /* get the filename */
  304.     while (!strchr(delim, c)) {
  305.  
  306.         /* don't add to fname if maximum length reached */
  307.         if (length < max_length - 1) {
  308.             *s++ = c;
  309.             length++;
  310.         }
  311.         c = (char) fgetc(list_file);
  312.         if (feof(list_file)) {
  313.             *s = '\0';
  314.             return TRUE;
  315.         }
  316.     }
  317.  
  318.     /* success */
  319.     *s = '\0';
  320.     return TRUE;
  321. }
  322.  
  323.  
  324. /*----------------------------------------------------------------------------
  325.  *
  326.  * Process() tags the input stream from the input file and outputs to a
  327.  * temporary file which is registered in argf.
  328.  *
  329.  ---------------------------------------------------------------------------*/
  330.  
  331. void Process(FILE * infile, char *infname, FILE * outfile, Flags * flags)
  332. {
  333.     /* log the input filename */
  334.     log_message(infname);
  335.  
  336.     switch (flags->tag_type) {
  337.  
  338.         case C:         /* use C type parsing */
  339.             CTags(infile, infname, outfile, flags);
  340.             break;
  341.  
  342.         case ASM:               /* use ASM type parsing */
  343.             ASMTags(infile, infname, outfile, flags);
  344.             break;
  345.  
  346.         default:
  347.             break;
  348.     }
  349. }
  350.  
  351.  
  352. /*----------------------------------------------------------------------------
  353.  *
  354.  * SingleFileProcess() tags a single file and outputs to a temporary file
  355.  * registered in argf.  Wildcards are allowed as file names.
  356.  *
  357.  ---------------------------------------------------------------------------*/
  358.  
  359. void SingleFileProcess(char *pathname, Flags * flags,
  360.                         FILE * outfile, ArgList argInput,
  361.                         ArgList argInputRaw)
  362. {
  363.     char fname[MAXPATH + 1];    /* the current file name */
  364.     char full_pathname[MAXPATH + 1];    /* the full path and filename */
  365.     char tmpstr[2 * MAXPATH + 1];       /* error string */
  366.  
  367.     struct file_info_struct ff; /* the file find structure */
  368.  
  369.     FILE *input_file;           /* the input file being worked on */
  370.  
  371.     /* initialize ff */
  372.     strcpy(ff.file_pattern, pathname);
  373.     ff.file_attributes = _FA_NORMAL | _FA_READONLY | _FA_ARCHIVE |
  374.         _FA_HIDDEN | _FA_SYSTEM;
  375.  
  376.     /* find the initial file matching pattern */
  377.     if (!find_firstfile(&ff)) {
  378.  
  379.         /* bad file name */
  380.         sprintf(tmpstr, "# Could not find the file '%s'", pathname);
  381.         log_message(tmpstr);
  382.     }
  383.     else {
  384.  
  385.         /* loop through all matching files in the parameter */
  386.         do {
  387.  
  388.             /* make the file name */
  389.             strcpy(fname, ff.file_path);
  390.             strcat(fname, ff.file.name);
  391.  
  392.             /* get the fully qualified pathname if wanted */
  393.             if (!flags->use_relative_pathnames) {
  394.                 _fullpath(full_pathname, fname, MAXPATH);
  395.             }
  396.             else {
  397.                 strcpy(full_pathname, fname);
  398.             }
  399.  
  400.             /* convert pathname to lower case */
  401.             strlwr(full_pathname);
  402.  
  403.             /* register the original input file name after verifying that we
  404.              * have not previously processed this file */
  405.             if (!ArgIsMember(argInputRaw, full_pathname)) {
  406.  
  407.                 ArgRegisterName(argInput, full_pathname);
  408.                 ArgRegisterName(argInputRaw, full_pathname);
  409.  
  410.                 /* Try to open the file */
  411.                 if ((input_file = fopen(fname, "r")) == (FILE *) NULL) {
  412.                     sprintf(tmpstr,
  413.                             "# Could not open %s for Tagging", fname);
  414.                     log_message(tmpstr);
  415.                 }
  416.                 else {
  417.  
  418.                     /* perform the needed tagging function */
  419.                     Process(input_file, full_pathname, outfile, flags);
  420.  
  421.                     /* close the input file */
  422.                     fclose(input_file);
  423.                 }
  424.             }
  425.  
  426.         } while (find_nextfile(&ff));
  427.     }
  428. }
  429.  
  430.  
  431. /*----------------------------------------------------------------------------
  432.  *
  433.  * BatchFileProcess() tags a list of files within the file given.  Wildcards
  434.  * are allowed in the listing file and as the listing file name.
  435.  *
  436.  ---------------------------------------------------------------------------*/
  437.  
  438. void BatchFileProcess(char *pathname, Flags * flags,
  439.                        FILE * outfile, ArgList argInput,
  440.                        ArgList argInputRaw)
  441. {
  442.     FILE *list_file;            /* file with list of files */
  443.  
  444.     char list_filename[MAXPATH + 1];    /* the current file name */
  445.     char input_filename[MAXPATH + 1];   /* the current file name */
  446.     char tmpstr[2 * MAXPATH + 1];       /* error string */
  447.     struct file_info_struct ff; /* the file find structure */
  448.  
  449.     /* initialize ff */
  450.     strcpy(ff.file_pattern, pathname);
  451.     ff.file_attributes = _FA_NORMAL | _FA_READONLY | _FA_ARCHIVE |
  452.         _FA_HIDDEN | _FA_SYSTEM;
  453.  
  454.     /* find the initial file matching pattern */
  455.     if (!find_firstfile(&ff)) {
  456.  
  457.         /* bad file name */
  458.         sprintf(tmpstr,
  459.                 "# Could not find the listfile '%s'", pathname);
  460.         log_message(tmpstr);
  461.     }
  462.     else {
  463.  
  464.         /* loop through all available list files with pathname */
  465.         do {
  466.  
  467.             /* make the file name */
  468.             strcpy(list_filename, ff.file_path);
  469.             strcat(list_filename, ff.file.name);
  470.  
  471.             /* open the list file and parse the file */
  472.             if ((list_file = fopen(list_filename, "r")) ==
  473.                 (FILE *) NULL) {
  474.                 sprintf(tmpstr,
  475.                         "# Could not open %s as a listfile", list_filename);
  476.                 log_message(tmpstr);
  477.             }
  478.             else {
  479.  
  480.                 /* output the file we are parsing */
  481.                 sprintf(tmpstr,
  482.                         "# Opening listfile %s", list_filename);
  483.                 log_message(tmpstr);
  484.  
  485.                 /* loop while there are more filenames in the file */
  486.                 while (nextfile(list_file, input_filename, MAXPATH + 1)) {
  487.  
  488.                     /* do not tag this file set if seen before */
  489.                     if (!ArgIsMember(argInputRaw, input_filename)) {
  490.  
  491.                         /* tag the obtained file path */
  492.                         SingleFileProcess(input_filename, flags,
  493.                                           outfile, argInput, argInputRaw);
  494.  
  495.                         /* register the input file as seen in the list file */
  496.                         ArgRegisterArg(argInputRaw, input_filename);
  497.                     }
  498.                 }
  499.  
  500.                 /* close the list file */
  501.                 fclose(list_file);
  502.             }
  503.         } while (find_nextfile(&ff));
  504.     }
  505. }
  506.  
  507.  
  508. /*----------------------------------------------------------------------------
  509.  *
  510.  * SingleFileExclude() places a single file into argInputRaw ArgList to
  511.  * exclude a file from further processing.  Wildcards are allowed as file
  512.  * names.
  513.  *
  514.  ---------------------------------------------------------------------------*/
  515.  
  516. void SingleFileExclude(char *pathname, Flags * flags, ArgList argInputRaw)
  517. {
  518.     char fname[MAXPATH + 1];    /* the current file name */
  519.     char full_pathname[MAXPATH + 1];    /* the full path and filename */
  520.     struct file_info_struct ff; /* the file find structure */
  521.  
  522.     /* initialize ff */
  523.     strcpy(ff.file_pattern, pathname);
  524.     ff.file_attributes = _FA_NORMAL | _FA_READONLY | _FA_ARCHIVE |
  525.         _FA_HIDDEN | _FA_SYSTEM;
  526.  
  527.     /* find the initial file matching pattern */
  528.     if (find_firstfile(&ff)) {
  529.  
  530.         /* loop through all matching files in the parameter */
  531.         do {
  532.  
  533.             /* make the file name */
  534.             strcpy(fname, ff.file_path);
  535.             strcat(fname, ff.file.name);
  536.  
  537.             /* get the fully qualified pathname if wanted */
  538.             if (!flags->use_relative_pathnames) {
  539.                 _fullpath(full_pathname, fname, MAXPATH);
  540.             }
  541.             else {
  542.                 strcpy(full_pathname, fname);
  543.             }
  544.  
  545.             /* convert pathname to lower case */
  546.             strlwr(full_pathname);
  547.  
  548.             /* register the original input file name after verifying that we
  549.              * have not previously processed this file */
  550.             if (!ArgIsMember(argInputRaw, full_pathname)) {
  551.  
  552.                 ArgRegisterName(argInputRaw, full_pathname);
  553.             }
  554.  
  555.         } while (find_nextfile(&ff));
  556.     }
  557. }
  558.  
  559.  
  560. /*----------------------------------------------------------------------------
  561.  *
  562.  * BatchFileExclude() places a list of files within the argInputRaw ArgList
  563.  * to inhibit processing of those files.  Wildcards are allowed in the
  564.  * listing file and as the listing file name.
  565.  *
  566.  ---------------------------------------------------------------------------*/
  567.  
  568. void BatchFileExclude(char *pathname, Flags * flags, ArgList argInputRaw)
  569. {
  570.     FILE *list_file;            /* file with list of files */
  571.  
  572.     char list_filename[MAXPATH + 1];    /* the current file name */
  573.     char input_filename[MAXPATH + 1];   /* the current file name */
  574.     struct file_info_struct ff; /* the file find structure */
  575.  
  576.     /* initialize ff */
  577.     strcpy(ff.file_pattern, pathname);
  578.     ff.file_attributes = _FA_NORMAL | _FA_READONLY | _FA_ARCHIVE |
  579.         _FA_HIDDEN | _FA_SYSTEM;
  580.  
  581.     /* find the initial file matching pattern */
  582.     if (!find_firstfile(&ff)) {
  583.  
  584.         /* bad file name */
  585.         fprintf(stderr,
  586.                 "# Could not find the Exclude listfile '%s'", pathname);
  587.         exit(1);
  588.     }
  589.     else {
  590.  
  591.         /* loop through all available list files with pathname */
  592.         do {
  593.  
  594.             /* make the file name */
  595.             strcpy(list_filename, ff.file_path);
  596.             strcat(list_filename, ff.file.name);
  597.  
  598.             /* open the list file and parse the file */
  599.             if ((list_file = fopen(list_filename, "r")) ==
  600.                 (FILE *) NULL) {
  601.                 fprintf(stderr,
  602.                         "# Could not open %s as an Exclude listfile",
  603.                         list_filename);
  604.                 exit(1);
  605.             }
  606.             else {
  607.  
  608.                 /* make the file name */
  609.                 strcpy(list_filename, ff.file_path);
  610.                 strcat(list_filename, ff.file.name);
  611.  
  612.                 /* loop while there are more filenames in the file */
  613.                 while (nextfile(list_file, input_filename, MAXPATH + 1)) {
  614.  
  615.                     /* do not register this file set if seen before */
  616.                     if (!ArgIsMember(argInputRaw, input_filename)) {
  617.  
  618.                         /* exclude the obtained file path */
  619.                         SingleFileExclude(input_filename, flags, argInputRaw);
  620.  
  621.                         /* register the input file as seen in the list file */
  622.                         ArgRegisterArg(argInputRaw, input_filename);
  623.                     }
  624.                 }
  625.  
  626.                 /* close the list file */
  627.                 fclose(list_file);
  628.             }
  629.  
  630.         } while (find_nextfile(&ff));
  631.     }
  632. }
  633.  
  634.  
  635. /*----------------------------------------------------------------------------
  636.  *
  637.  * Validate() calls the CRC validation routines and exits with a warning if
  638.  * there are problems.
  639.  *
  640.  ---------------------------------------------------------------------------*/
  641.  
  642. void Validate(char *filename)
  643. {
  644.     /* validate the executable against the internally stored CRC */
  645.     switch (validatecrc(filename)) {
  646.  
  647.             case CRC_VALID:
  648.  
  649.             break;
  650.  
  651.         case CRC_INVALID:
  652.         case CRC_ISZERO:
  653.  
  654.             /* internal failure */
  655.             fprintf(stderr,
  656.                     "This executable fails internal CRC checking due to ");
  657.             fprintf(stderr,
  658.                     "external modification. \n");
  659.             fprintf(stderr,
  660.                     "Please validate this copy and scan for virus ");
  661.             fprintf(stderr, "infection.\n");
  662.             exit(1);
  663.             break;
  664.  
  665.         case CRC_NOMEM:
  666.  
  667.             fprintf(stderr,
  668.                     "Error - Out of Memory\n");
  669.             exit(1);
  670.             break;
  671.  
  672.         case CRC_FILEERR:
  673.  
  674.             fprintf(stderr,
  675.                     "Error - Program file not found\n");
  676.             exit(1);
  677.             break;
  678.  
  679.         default:
  680.  
  681.             break;
  682.     }
  683. }
  684.  
  685.  
  686. /*----------------------------------------------------------------------------
  687.  *
  688.  * main loops through the parameter list and calls the appropriate parsers
  689.  *
  690.  ---------------------------------------------------------------------------*/
  691.  
  692. int main(int argc, char *argv[])
  693. {
  694.     Flags flags;
  695.  
  696.     char log_filename[MAXPATH]; /* log file name */
  697.     char output_filename[MAXPATH];      /* the tag file to output to */
  698.     char tmpstr[2 * MAXPATH + 1];       /* error and temp string */
  699.  
  700.     char *environ_ptr;          /* holds pointer to TMP variable */
  701.     int environ_len;            /* holds length of TMP variable */
  702.  
  703.     ArgList argSort;            /* the list of files sent to sort */
  704.     ArgList argInput;           /* the list of input files */
  705.     ArgList argInputRaw;        /* the list of command line input files and
  706.                                  * files which are excluded */
  707.  
  708.     struct tm *now;             /* clock variables */
  709.     time_t cur_clock;
  710.  
  711.     unsigned int i;             /* temp looping var */
  712.     int switch_count;           /* the number of switches found */
  713.  
  714.     char drive[5], dir[255], fname[10], ext[5];
  715.  
  716.     FILE *output_stream;        /* the output stream */
  717.     FILE *tag_stream;           /* the stream for temporary output */
  718.  
  719.     /* Register CTRL+C handler. */
  720.     signal(SIGINT, CtrlCHandler);
  721.  
  722.     /* validate the executable against the internally stored CRC */
  723.     Validate(argv[0]);
  724.  
  725.     /* obtain parts of the startup path */
  726.     _splitpath(argv[0], drive, dir, fname, ext);
  727.  
  728.     /* if not enough parameters than Usage() */
  729.     if (argc < 2)
  730.         Usage(fname);
  731.  
  732.     /* compute the current time */
  733.     time(&cur_clock);
  734.     now = localtime(&cur_clock);
  735.  
  736.     /* initialize flags structure */
  737.     init_flags(&flags);
  738.  
  739.     /* the initial file stuff */
  740.     log_filename[0] = '\0';
  741.     output_filename[0] = '\0';
  742.     output_stream = stdout;
  743.  
  744.     /* get the TMP environment variable */
  745.     environ_ptr = getenv("TMP");
  746.     environ_len = strlen(environ_ptr);
  747.  
  748.     /* obtain the intermediate tag filename */
  749.     if (environ_len &&
  750.         environ_ptr[environ_len - 1] != '\\' &&
  751.         environ_ptr[environ_len - 1] != '/')
  752.         tmp_tagfilename = tempnam("\\", "tg");
  753.     else
  754.         tmp_tagfilename = tempnam("", "tg");
  755.  
  756.     /* verify filename allocation */
  757.     if (tmp_tagfilename == NULL) {
  758.         fprintf(stderr, "# Could not create temporary files for output");
  759.         exit(1);
  760.     }
  761.  
  762.     /* init arglist variable */
  763.     argSort = CreateArgList(ARGLIST_NORMAL);
  764.     argInput = CreateArgList(ARGLIST_SORTED);
  765.     argInputRaw = CreateArgList(ARGLIST_SORTED);
  766.  
  767.     /* preparse for global switches */
  768.     switch_count = 0;
  769.     for (i = 1; i < (unsigned) argc; i++) {
  770.  
  771.         switch (argv[i][0]) {
  772.  
  773.             case '/':
  774.             case '-':
  775.                 switch_count++;
  776.                 switch (argv[i][1]) {
  777.                     case 'l':   /* tag from file list */
  778.                     case 'L':
  779.  
  780.                         /* filename must hug the switch */
  781.                         if (strlen(argv[i] + 2)) {
  782.                             strcpy(log_filename, argv[i] + 2);
  783.                         }
  784.                         else {
  785.                             fprintf(stderr,
  786.                                     "# -l switch used incorrectly\n");
  787.                             exit(1);
  788.                         }
  789.  
  790.                         /* set overwrite flag */
  791.                         if (argv[i][1] == 'l') {
  792.                             flags.log_overwrite = TRUE;
  793.                         }
  794.                         else {
  795.                             flags.log_overwrite = FALSE;
  796.                         }
  797.  
  798.                         break;
  799.  
  800.                     case 't':   /* send to tag file */
  801.                     case 'T':
  802.  
  803.                         /* filename must hug the switch */
  804.                         if (strlen(argv[i] + 2)) {
  805.                             strcpy(output_filename, argv[i] + 2);
  806.                             if (environ_len &&
  807.                                 environ_ptr[environ_len - 1] != '\\' &&
  808.                                 environ_ptr[environ_len - 1] != '/')
  809.                                 tmp_filename = tempnam("\\", "tg");
  810.                             else
  811.                                 tmp_filename = tempnam("", "tg");
  812.  
  813.                             /* verify filename allocation */
  814.                             if (tmp_filename == NULL) {
  815.                                 fprintf(stderr,
  816.                                         "# Could not create temporary files for output");
  817.                                 exit(1);
  818.                             }
  819.                         }
  820.                         else {
  821.                             fprintf(stderr,
  822.                                     "# -t switch used incorrectly\n");
  823.                             exit(1);
  824.                         }
  825.  
  826.                         /* set output flag */
  827.                         flags.output_file = TRUE;
  828.                         break;
  829.  
  830.                     case 'n':   /* do not sort the output */
  831.                     case 'N':
  832.  
  833.                         /* set tag_type */
  834.                         flags.sort_tags = FALSE;
  835.                         break;
  836.  
  837.                     case 'm':   /* merge files only */
  838.                     case 'M':
  839.  
  840.                         /* set tag_type */
  841.                         flags.tag_type = MERGE;
  842.                         break;
  843.  
  844.                     case 's':   /* sort files only */
  845.                     case 'S':
  846.  
  847.                         /* set tag_type */
  848.                         flags.tag_type = SORT;
  849.                         break;
  850.  
  851.                     case 'o':   /* output format specifier follows */
  852.                     case 'O':   /* the last format found is the one */
  853.  
  854.                         /* set the option modifier */
  855.                         parse_output_flags(argv[i], &flags);
  856.                         break;
  857.  
  858.                     case 'r':   /* output format specifier follows */
  859.                     case 'R':   /* the last format found is the one */
  860.  
  861.                         /* set to use relative pathnames */
  862.                         flags.use_relative_pathnames = TRUE;
  863.                         break;
  864.  
  865.                     case 'q':   /* use quiet mode (no logging to stderr) */
  866.                     case 'Q':
  867.                         flags.quiet = TRUE;
  868.                         break;
  869.  
  870.                     case 'i':   /* use case sensitive sort */
  871.                     case 'I':
  872.                         flags.case_sensitive = TRUE;
  873.                         break;
  874.  
  875.                     case 'x':   /* exclude this file or filelist */
  876.                     case 'X':
  877.                         /* filename must hug the switch */
  878.                         if (!strlen(argv[i] + 2)) {
  879.                             fprintf(stderr,
  880.                                     "# -x switch used incorrectly\n");
  881.                             exit(1);
  882.                         }
  883.                         else {
  884.  
  885.                             /* check if list file exclude or normal file
  886.                              * exclude */
  887.  
  888.                             if (argv[i][2] != '@') {
  889.  
  890.                                 /* this is a particular exclusion */
  891.                                 /* do not use this Exclude file if seen
  892.                                  * previously */
  893.                                 if (!ArgIsMember(argInputRaw, argv[i] + 2)) {
  894.  
  895.                                     /* process the Exclude file */
  896.                                     SingleFileExclude(argv[i] + 2, &flags,
  897.                                                       argInputRaw);
  898.  
  899.                                     /* register the input list file as seen
  900.                                      * on the command line */
  901.                                     ArgRegisterArg(argInputRaw, argv[i] + 2);
  902.                                 }
  903.                             }
  904.                             else {
  905.  
  906.                                 /* this is an exclusion list file */
  907.                                 if (strlen(argv[i] + 3)) {
  908.  
  909.                                     /* do not use this Exclude list file if
  910.                                      * seen previously */
  911.                                     if (!ArgIsMember(argInputRaw,
  912.                                                      argv[i] + 3)) {
  913.  
  914.                                         /* process the list file */
  915.                                         BatchFileExclude(argv[i] + 3, &flags,
  916.                                                          argInputRaw);
  917.  
  918.                                         /* register the input list file as
  919.                                          * seen on the command line */
  920.                                         ArgRegisterArg(argInputRaw,
  921.                                                        argv[i] + 3);
  922.                                     }
  923.                                 }
  924.                                 else {
  925.                                     fprintf(stderr,
  926.                                             "# @ syntax error");
  927.                                     exit(1);
  928.                                 }
  929.                             }
  930.                         }
  931.                         break;
  932.  
  933.                     case 'h':
  934.                     case 'H':
  935.                         Help(fname);
  936.                         break;
  937.  
  938.                     default:
  939.                         break;
  940.                 }
  941.                 break;
  942.  
  943.             default:
  944.                 break;
  945.         }
  946.     }
  947.  
  948.     /* exit if no input files specified */
  949.     if (switch_count == argc - 1) {
  950.         fprintf(stderr,
  951.                 "# No input files specified\n");
  952.         exit(1);
  953.     }
  954.  
  955.     /* open the log file */
  956.     if (!log_open(log_filename, flags.quiet, flags.log_overwrite)) {
  957.         fprintf(stderr,
  958.                 "# Could not open %s as a logfile\n", log_filename);
  959.         exit(1);
  960.     }
  961.  
  962.     /* open the temporary tag file */
  963.     if ((tag_stream = fopen(tmp_tagfilename, "w")) ==
  964.         (FILE *) NULL) {
  965.         sprintf(tmpstr,
  966.                 "# Internal error opening temporary files");
  967.         log_message(tmpstr);
  968.         exit(1);
  969.     }
  970.  
  971.     /* print initial messages */
  972.     sprintf(tmpstr, "# %s %s -- %s", Version, CompileDate, Author);
  973.     log_message(tmpstr);
  974.     sprintf(tmpstr, "# Tagging performed: %s#", asctime(now));
  975.     log_message(tmpstr);
  976.  
  977.     if (flags.tag_type == MERGE) {
  978.         log_message("# Merging previously processed tag files");
  979.     }
  980.  
  981.     if (flags.tag_type == SORT) {
  982.         log_message("# Sorting input files only");
  983.     }
  984.  
  985.     /* enter the main loop */
  986.     for (argc--, argv++; argc; argc--, argv++) {
  987.  
  988.         /* parse the argument list */
  989.         switch (argv[0][0]) {
  990.             case '@':
  991.                 if (strlen(argv[0] + 1)) {
  992.  
  993.                     /* do not use this list file if seen previously */
  994.                     if (!ArgIsMember(argInputRaw, argv[0] + 1)) {
  995.  
  996.                         /* process the list file */
  997.                         BatchFileProcess(argv[0] + 1, &flags,
  998.                                          tag_stream, argInput,
  999.                                          argInputRaw);
  1000.  
  1001.                         /* register the input list file as seen on the
  1002.                          * command line */
  1003.                         ArgRegisterArg(argInputRaw, argv[0] + 1);
  1004.                     }
  1005.                     break;
  1006.                 }
  1007.                 else {
  1008.                     log_message("# @ syntax error");
  1009.                 }
  1010.                 break;
  1011.  
  1012.             case '/':
  1013.             case '-':
  1014.                 switch (argv[0][1]) {
  1015.                     case 'a':   /* use ASM tagging scheme */
  1016.                     case 'A':
  1017.  
  1018.                         /* ignore if merge or sort tag_types */
  1019.                         if (flags.tag_type != MERGE &&
  1020.                             flags.tag_type != SORT) {
  1021.  
  1022.                             /* set the option flags */
  1023.                             parse_ASM_flags(*argv, &flags);
  1024.                         }
  1025.                         break;
  1026.  
  1027.                     case 'c':   /* use C tagging scheme */
  1028.                     case 'C':
  1029.  
  1030.                         /* ignore if merge or sort tag_types */
  1031.                         if (flags.tag_type != MERGE &&
  1032.                             flags.tag_type != SORT) {
  1033.  
  1034.                             /* set the option flags */
  1035.                             parse_C_flags(*argv, &flags);
  1036.                         }
  1037.                         break;
  1038.  
  1039.                     default:
  1040.                         break;
  1041.                 }
  1042.                 break;
  1043.  
  1044.             default:
  1045.  
  1046.                 /* this is a file parameter */
  1047.                 /* do not tag this file set if seen previously */
  1048.                 if (!ArgIsMember(argInputRaw, *argv)) {
  1049.  
  1050.                     /* process the file */
  1051.                     SingleFileProcess(*argv, &flags, tag_stream,
  1052.                                       argInput, argInputRaw);
  1053.  
  1054.                     /* register the input file as seen on the command line */
  1055.                     ArgRegisterArg(argInputRaw, *argv);
  1056.                 }
  1057.                 break;
  1058.         }
  1059.     }
  1060.  
  1061.     /* free the command line input arglist */
  1062.     DestroyArgList(argInputRaw);
  1063.  
  1064.     /* close the intermediate tag file */
  1065.     fclose(tag_stream);
  1066.  
  1067.     /* do the sorting and collating */
  1068.     if (argInput->num_args) {
  1069.  
  1070.         /* register elements needed for the sort module unless no sorting is
  1071.          * requested */
  1072.         if (flags.sort_tags) {
  1073.  
  1074.             /* register the file name in argf */
  1075.             ArgRegisterArg(argSort, argv[0]);
  1076.  
  1077.             /* add the sort parameters to beginning of the name register
  1078.              * array */
  1079.             ArgRegisterArg(argSort, "-u");      /* delete duplicate lines */
  1080.  
  1081.             /* if not a case sensitive sort then register case fold */
  1082.             if (!flags.case_sensitive)
  1083.                 ArgRegisterArg(argSort, "-f");  /* fold to lower case */
  1084.  
  1085.             /* if merge then add argument to sort parameters */
  1086.             if (flags.tag_type == MERGE)
  1087.                 ArgRegisterArg(argSort, "-m");  /* merge sort files */
  1088.  
  1089.             /* if output file specified then tmp_filename as output */
  1090.             if (flags.output_file &&
  1091.                 flags.tag_type != MERGE &&
  1092.                 flags.tag_type != SORT) {
  1093.                 sprintf(tmpstr, "-o%s", tmp_filename);
  1094.                 ArgRegisterArg(argSort, tmpstr);
  1095.             }
  1096.  
  1097.             if (flags.tag_type == MERGE ||
  1098.                 flags.tag_type == SORT) {
  1099.  
  1100.                 /* copy the names from ArgInput to ArgSort */
  1101.                 ArgCopy(argSort, argInput);
  1102.             }
  1103.             else {
  1104.                 /* register the intermediate tag file to be sorted */
  1105.                 ArgRegisterName(argSort, tmp_tagfilename);
  1106.             }
  1107.  
  1108.             /* log the activity */
  1109.             if (flags.tag_type == MERGE) {
  1110.                 log_message("# Merging Input Files...");
  1111.             }
  1112.             else {
  1113.                 log_message("# Sorting ...");
  1114.             }
  1115.  
  1116.             /* perform the sort */
  1117.             sort_main(argSort->num_args, argSort->argv);
  1118.         }
  1119.         else {
  1120.  
  1121.             /* register the intermediate tag file to be sorted */
  1122.             ArgRegisterName(argSort, tmp_tagfilename);
  1123.  
  1124.             /* open a temporary file if using an output file */
  1125.             if (flags.output_file) {
  1126.  
  1127.                 /* open the file before writing it */
  1128.                 if ((output_stream = fopen(tmp_filename, "w")) ==
  1129.                     (FILE *) NULL) {
  1130.                     sprintf(tmpstr,
  1131.                             "# Internal error opening temporary files");
  1132.                     log_message(tmpstr);
  1133.                     exit(1);
  1134.                 }
  1135.             }
  1136.  
  1137.             /* output the results */
  1138.             ArgToOutputStream(output_stream, argSort);
  1139.  
  1140.             /* close the output file if necessary */
  1141.             if (flags.output_file) {
  1142.                 fclose(output_stream);
  1143.             }
  1144.         }
  1145.     }
  1146.  
  1147.  
  1148.     /* merge the temporary output file and the current tag file */
  1149.     if (flags.output_file &&
  1150.         argInput->num_args) {
  1151.         log_message("# Merging into tag file ...");
  1152.         MergeFile(tmp_filename, output_filename, argInput, &flags);
  1153.     }
  1154.  
  1155.     /* delete the temporary file if used and free its memory */
  1156.     if (flags.output_file) {
  1157.         remove(tmp_filename);
  1158.         free(tmp_filename);
  1159.     }
  1160.  
  1161.     /* delete the intermediate tags file and free its memory */
  1162.     remove(tmp_tagfilename);
  1163.     free(tmp_tagfilename);
  1164.  
  1165.     /* list the number of files tagged and closing message */
  1166.     sprintf(tmpstr,
  1167.             "# Tagging operation complete with %u file(s) tagged\n",
  1168.             argInput->num_args);
  1169.     log_message(tmpstr);
  1170.  
  1171.     /* free the arglist structures */
  1172.     DestroyArgList(argSort);
  1173.     DestroyArgList(argInput);
  1174.  
  1175.     /* close the log file */
  1176.     log_close();
  1177.  
  1178.     /* successful exit */
  1179.     return (0);
  1180. }
  1181.